package globalVisionEntertainment.nba;

import gqqnbig.SystemHelper;
import gqqnbig.jsoup.AdaptiveDownloader;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.MessageFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

public class Program
{

	private static final Path nameTranslationDir = Paths.get(SystemHelper.getAppPath(Program.class), "Name Translation Files");
	private static final String additionalNameTranslationFileName = "Additional Name Translation.html";

	private static final String additionalNameTranslationFileInstruction = String.format("Consider adding an entry in %s by your text editor.",
			nameTranslationDir.resolve(additionalNameTranslationFileName).toString());
	private static final AdaptiveDownloader basketballReferenceDownloader = new AdaptiveDownloader();

	public static void main(String[] args) throws Exception
	{
		String playerName;// = "Kenneth Faried";
		String date;// = "2014-03-26";

		if (args.length != 2)
			throw new IllegalArgumentException("You have to give two arguments, namely player name and date of the game.");
		playerName = args[0];
		date = args[1];

		refreshPlayerNameTranslationFile();

		String playerId = getPlayerId(playerName);

		Element dataRow = getDataRow(date, playerId);
		if (dataRow == null)
			throw new IllegalArgumentException(MessageFormat.format("Unable to get the game information by {0} on {1} from www.basketball-reference.com.\n"
					+ "Are there more than one {0}? " + additionalNameTranslationFileInstruction, playerName, date));

		String FG, FGA, _3P, _3PA, FT, FTA, ORB, DRB, TRB, AST, STL, BLK, TOV, PF, PTS;

		FG = dataRow.select("td:nth-child(11)").text();
		FGA = dataRow.select("td:nth-child(12)").text();
		_3P = dataRow.select("td:nth-child(14)").text();
		_3PA = dataRow.select("td:nth-child(15)").text();
		FT = dataRow.select("td:nth-child(17)").text();
		FTA = dataRow.select("td:nth-child(18)").text();
		ORB = dataRow.select("td:nth-child(20)").text();
		DRB = dataRow.select("td:nth-child(21)").text();
		TRB = dataRow.select("td:nth-child(22)").text();
		AST = dataRow.select("td:nth-child(23)").text();
		STL = dataRow.select("td:nth-child(24)").text();
		BLK = dataRow.select("td:nth-child(25)").text();
		TOV = dataRow.select("td:nth-child(26)").text();
		PF = dataRow.select("td:nth-child(27)").text();
		PTS = dataRow.select("td:nth-child(28)").text();

		Class.forName("com.mysql.jdbc.Driver");
		Connection conn = null;
		String sql = "";
		try
		{
			conn = Database.getConnection();
			conn.setAutoCommit(true);

			java.sql.CallableStatement statement = conn.prepareCall("{call getGameIdByPlayerAndDate(?,?,?)}");
			statement.setString(1, playerName);
			statement.setString(2, date);
			statement.registerOutParameter(3, java.sql.Types.INTEGER);
			statement.execute();
			int gameId = statement.getInt(3);

			//@formatter:off
			sql=String.format("update `playerstatistic`"+
"set `FG` =%s,"+
"`FGA` =%s,"+
"`3P` =%s,"+
"`3PA` =%s,"+
"`FT` =%s,"+
"`FTA` =%s,"+
"`ORB` =%s,"+
"`DRB` =%s,"+
"`TRB` =%s,"+
"`AST` =%s,"+
"`STL` =%s,"+
"`BLK` =%s,"+
"`TOV` =%s,"+
"`PF` =%s,"+
"`PTS` =%s \n"+
"where `PlayerName`=\"%s\" and `game`=%s",
	FG, FGA, _3P, _3PA, FT, FTA, ORB, DRB, TRB, AST, STL, BLK, TOV, PF, PTS,
	playerName,gameId);
			//@formatter:on

			// System.out.println(sql);
			Statement statement2 = conn.createStatement();
			statement2.execute(sql);
			if (statement2.getUpdateCount() != 1)
				throw new UnsupportedOperationException(MessageFormat.format("Updated {0} rows; 1 is expected.", statement2.getUpdateCount()));

		}
		catch (SQLException e)
		{
			System.err.println(args[0] + ", " + args[1]);
			System.err.println("Operating database Failed."); // Is the service running?
			System.err.println(e.toString());
			System.err.println(sql);
		}
		catch (Exception e)
		{
			System.err.println(args);
			System.err.println(e.toString());
		}
		finally
		{
			if (conn != null)
				conn.close();
		}
	}

	private static Element getDataRow(String dateString, String playerId) throws IOException, ParseException
	{
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
		Date date;
		date = dateFormat.parse(dateString);
		// 不要用EST。EST不考虑夏令时。
		Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("America/New_York"));
		calendar.setTime(date);
		int year = calendar.get(Calendar.YEAR);
		if (calendar.get(Calendar.MONTH) >= 7)
			year++;

		Document document;

		File cache = Paths.get(System.getProperty("java.io.tmpdir"), "head2head cache", playerId + Integer.toString(year) + ".html").toFile();
		cache.getParentFile().mkdirs();
		if (cache.exists() && System.currentTimeMillis() - cache.lastModified() < 7 * 24 * 3600)
		{
			document = Jsoup.parse(cache, "utf8");
		}
		else
		{
			document = basketballReferenceDownloader.parseWebDocument(
					String.format("http://www.basketball-reference.com/players/%s/%s/gamelog/%s/", playerId.charAt(0), playerId, year), 3);
			String str = document.html();
			FileWriter fw = new FileWriter(cache);
			BufferedWriter bfw = new BufferedWriter(fw);
			bfw.write(str, 0, str.length());
			bfw.close();
		}

		Elements elements = document.select("#pgl_basic > tbody td:nth-child(3), #pgl_basic_playoffs > tbody td:nth-child(3)");
		for (Element element : elements)
		{
			if (element.text().equals(dateString))
				return (Element) element.parentNode();
		}
		return null;
	}

	private static void refreshPlayerNameTranslationFile() throws Exception
	{

		File file = nameTranslationDir.resolve("a.html").toFile();

		if (file.exists())
		{
			long time = file.lastModified();

			long currentTime = System.currentTimeMillis();

			// System.out.println(time);
			// System.out.println(currentTime);

			if (currentTime - 1000 * 3600 * 24 * 7 < time)
				return;
		}
		else
			nameTranslationDir.toFile().mkdirs();

		for (int i = 'a'; i <= 'z'; i++)
		{
			char initial = (char) i;
			//@formatter:off
			Document document = basketballReferenceDownloader.parseWebDocument("http://www.basketball-reference.com/play-index/get_player_names.cgi?html=1&form_id=h2h_finder&dummy=1&init="+ initial, 3);
			//@formatter:on
			String str = document.html();
			file = nameTranslationDir.resolve(initial + ".html").toFile();
			FileWriter fw = new FileWriter(file);
			BufferedWriter bfw = new BufferedWriter(fw);
			bfw.write(str, 0, str.length());
			bfw.close();
		}
	}

	private static String getPlayerId(String playerName) throws IOException
	{
		// 先用用户定义的名称转换文件
		String nameId = getPlayerIdInTranslationFile(nameTranslationDir.resolve(additionalNameTranslationFileName).toFile(), playerName);
		if (nameId != null)
			return nameId;

		// Nando de Colo： de Colo是姓，Nando是名。

		String[] parts = playerName.split(" ");
		if (parts.length != 2)
			throw new UnsupportedOperationException(String.format("The name %s has %s parts; don't know which is first name, which is last name. \n"
					+ additionalNameTranslationFileInstruction, playerName, parts.length));

		String firstName = parts[0];
		String lastName = parts[1];

		String text = lastName + ", " + firstName;

		String fileName = Character.toLowerCase(lastName.charAt(0)) + ".html";
		File file = nameTranslationDir.resolve(fileName).toFile();
		nameId = getPlayerIdInTranslationFile(file, text);
		if (nameId != null)
			return nameId;

		throw new IllegalArgumentException(MessageFormat.format("Unable to find player id of {0} in {1} and {2}.\n" + additionalNameTranslationFileInstruction, playerName,
				fileName, additionalNameTranslationFileName));
	}

	private static String getPlayerIdInTranslationFile(File file, String text) throws IOException
	{
		Document document = Jsoup.parse(file, "UTF8");
		Elements elements = document.select("option");
		for (Element element : elements)
		{
			if (element.text().equals(text))
				return element.attr("value");
		}
		return null;
	}

}
